﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Utils;
using NetworkModel;
using System.Windows;
using System.Diagnostics;
using DataLayer;
using System.Windows.Controls;
using System.Windows.Media;
namespace LuanVanProject
{
    /// <summary>
    /// The view-model for the main window.
    /// </summary>
    public class MainWindowViewModel : AbstractModelBase
    {
        #region Internal Data Members

        /// <summary>
        /// This is the network that is displayed in the window.
        /// It is the main part of the view-model.
        /// </summary>
        public NetworkViewModel network = null;
        

        public List<ActionCommand> commandList;
             

        ///
        /// The current scale at which the content is being viewed.
        /// 
        private double contentScale = 1;

        ///
        /// The X coordinate of the offset of the viewport onto the content (in content coordinates).
        /// 
        private double contentOffsetX = 0;

        ///
        /// The Y coordinate of the offset of the viewport onto the content (in content coordinates).
        /// 
        private double contentOffsetY = 0;

        ///
        /// The width of the content (in content coordinates).
        /// 
        private double contentWidth = 5000;

        ///
        /// The heigth of the content (in content coordinates).
        /// 
        private double contentHeight = 5000;

        ///
        /// The width of the viewport onto the content (in content coordinates).
        /// The value for this is actually computed by the main window's ZoomAndPanControl and update in the
        /// view-model so that the value can be shared with the overview window.
        /// 
        private double contentViewportWidth = 0;

        ///
        /// The height of the viewport onto the content (in content coordinates).
        /// The value for this is actually computed by the main window's ZoomAndPanControl and update in the
        /// view-model so that the value can be shared with the overview window.
        /// 
        private double contentViewportHeight = 0;

        #endregion Internal Data Members

        const int left = 1;
        const int right = 2;
        public List<Observer> listObserver;
        public MainWindowViewModel()
        {
            // Add some test data to the view-model.
           // PopulateWithTestData();
            this.listObserver = new List<Observer>();
            this.commandList = new List<ActionCommand>();
        }
        public void AddObserver(Observer ob)
        {
            listObserver.Add(ob);
        }
        private Node viewNode;

        public Node ViewNode
        {
            get { return viewNode; }
            set { viewNode = value; }
        }
        /// <summary>
        /// This is the network that is displayed in the window.
        /// It is the main part of the view-model.
        /// </summary>
        public NetworkViewModel Network
        {
            get
            {
                return network;
            }
            set
            {
                network = value;

                OnPropertyChanged("Network");
            }
        }

        ///
        /// The current scale at which the content is being viewed.
        /// 
        public double ContentScale
        {
            get
            {
                return contentScale;
            }
            set
            {
                contentScale = value;

                OnPropertyChanged("ContentScale");
            }
        }

        ///
        /// The X coordinate of the offset of the viewport onto the content (in content coordinates).
        /// 
        public double ContentOffsetX
        {
            get
            {
                return contentOffsetX;
            }
            set
            {
                contentOffsetX = value;

                OnPropertyChanged("ContentOffsetX");
            }
        }

        ///
        /// The Y coordinate of the offset of the viewport onto the content (in content coordinates).
        /// 
        public double ContentOffsetY
        {
            get
            {
                return contentOffsetY;
            }
            set
            {
                contentOffsetY = value;

                OnPropertyChanged("ContentOffsetY");
            }
        }

        ///
        /// The width of the content (in content coordinates).
        /// 
        public double ContentWidth
        {
            get
            {
                return contentWidth;
            }
            set
            {
                contentWidth = value;

                OnPropertyChanged("ContentWidth");
            }
        }

        ///
        /// The heigth of the content (in content coordinates).
        /// 
        public double ContentHeight
        {
            get
            {
                return contentHeight;
            }
            set
            {
                contentHeight = value;

                OnPropertyChanged("ContentHeight");
            }
        }

        ///
        /// The width of the viewport onto the content (in content coordinates).
        /// The value for this is actually computed by the main window's ZoomAndPanControl and update in the
        /// view-model so that the value can be shared with the overview window.
        /// 
        public double ContentViewportWidth
        {
            get
            {
                return contentViewportWidth;
            }
            set
            {
                contentViewportWidth = value;

                OnPropertyChanged("ContentViewportWidth");
            }
        }

        ///
        /// The heigth of the viewport onto the content (in content coordinates).
        /// The value for this is actually computed by the main window's ZoomAndPanControl and update in the
        /// view-model so that the value can be shared with the overview window.
        /// 
        public double ContentViewportHeight
        {
            get
            {
                return contentViewportHeight;
            }
            set
            {
                contentViewportHeight = value;
                OnPropertyChanged("ContentViewportHeight");
            }
        }



        public ConnectionViewModel FindConnectionExac(ConnectorViewModel source, ConnectorViewModel dest)
        {
            foreach (var connection in source.AttachedConnections)
            {
                if (connection.DestConnector == dest)
                {
                    //
                    // Found a connection that is outgoing from the source connector
                    // and incoming to the destination connector.
                    //
                    return connection;
                }
            }
            return null;
        }


        /// <summary>
        /// Retrieve a connection between the two connectors.
        /// Returns null if there is no connection between the connectors.
        /// </summary>
        public ConnectionViewModel FindConnection(ConnectorViewModel connector1, ConnectorViewModel connector2)
        {
            if (connector1.Type != ConnectorType.Undefined && connector2.Type != ConnectorType.Undefined)
            {
                Trace.Assert(connector1.Type != connector2.Type);

                //
                // Figure out which one is the source connector and which one is the
                // destination connector based on their connector types.
                //
                var sourceConnector = connector1.Type == ConnectorType.Output ? connector1 : connector2;
                var destConnector = connector1.Type == ConnectorType.Output ? connector2 : connector1;
                // var sourceConnector = connector1;
                //  var destConnector = connector2;
                //
                // Now we can just iterate attached connections of the source
                // and see if it each one is attached to the destination connector.
                //

                foreach (var connection in sourceConnector.AttachedConnections)
                {
                    if (connection.DestConnector == destConnector)
                    {
                        //
                        // Found a connection that is outgoing from the source connector
                        // and incoming to the destination connector.
                        //
                        return connection;
                    }
                }
            }
            return null;
        }


        /// <summary>
        /// Retrieve list connections between the out connector and anothor.
        /// 
        /// </summary>
        public List<ConnectionViewModel> FindListConnection(ConnectorViewModel outConnector)
        {
            List<ConnectionViewModel> rs = new List<ConnectionViewModel>();
            foreach (var connection in outConnector.AttachedConnections)
                {
                    rs.Add(connection);                    
                }
          
            return rs;
        }
        /// <summary>
        /// Delete the currently selected nodes from the view-model.
        /// </summary>
        public void DeleteSelectedNodes()
        {
            // Take a copy of the selected nodes list so we can delete nodes while iterating.
            var nodesCopy = this.Network.Nodes.ToArray();
            foreach (var node in nodesCopy)
            {
                if (node.IsSelected)
                {
                    DeleteNode(node);
                }
            }
            App.Synchronize();
        }


        //public void DeleteNodesAndChildren(NodeViewModel nodeVM)
        //{
        //    List<ConnectionViewModel> listConnection = new List<ConnectionViewModel>();
        //    if (nodeVM.LeftConnectors[0].Type == ConnectorType.Output)
        //    {
        //        listConnection.AddRange(FindListConnection(nodeVM.LeftConnectors[0]));
        //    }
        //    if (nodeVM.RightConnectors[0].Type == ConnectorType.Output)
        //    {
        //        listConnection.AddRange(FindListConnection(nodeVM.RightConnectors[0]));
        //    }
        //    for (int i = 0; i < listConnection.Count; i++)
        //    {
        //        NodeViewModel destNodeVM = listConnection[i].DestConnector.OwnerNode;
        //        this.Network.Connections.RemoveRange(nodeVM.AttachedConnections);
        //        DeleteNodesAndChildren(destNodeVM);
        //    }
        //    DeleteParentNode(nodeVM);
        //}

        /// <summary>
        /// Delete the node from the view-model.
        /// Also deletes any connections to or from the node.
        /// </summary>
        public void DeleteParentNode(NodeViewModel node)
        {
            this.Network.Nodes.Remove(node);
        }

        /// <summary>
        /// Delete the node from the view-model.
        /// Also deletes any connections to or from the node.
        /// </summary>
        public void DeleteNode(NodeViewModel node)
        {
            ////
            //// Remove all connections attached to the node.
            ////
            //this.Network.Connections.RemoveRange(node.AttachedConnections);

            ////
            //// Remove the node from the network.
            ////
            //this.Network.Nodes.Remove(node);
            AddCommandDelete(node.NodeData);
            viewNode.DelecteNode(node.NodeData);
            App.Synchronize();
        }

        public void ExpanChildNode(NodeViewModel node)
        {
           // node.Visibility = Visibility.Hidden;
            if (node.IsExpanded)
            {
                ExpandNode(node, Visibility.Hidden);
                node.IsExpanded = false;
            }
            else
            {
                ExpandNode(node, Visibility.Visible);
                node.IsExpanded = true;
            }
           
        }


        private void HideConnection(NodeViewModel _node)
        {
            
            CheckConnectorAndHide(_node.LeftConnectors[0]);
            CheckConnectorAndHide(_node.RightConnectors[0]);
        
        }

        private void ExpandNode(NodeViewModel _node,Visibility _visibility)
        {
            Check4Visibility(_node.LeftConnectors[0],_visibility);
            Check4Visibility(_node.RightConnectors[0],_visibility);
        }

        private void Check4Visibility(ConnectorViewModel _connector, Visibility _visibility)
        {
           
                ImpObservableCollection<ConnectionViewModel> leftConnections = _connector.AttachedConnections;
                foreach (ConnectionViewModel connection in leftConnections)
                {
                    string sourceName = connection.SourceConnector.OwnerNode.Name;
                    if(sourceName.Equals(_connector.OwnerNode.Name))
                        connection.Visibility = _visibility;
                }
            
        }

        private void CheckConnectorAndHide(ConnectorViewModel _connector)
        {
            if (_connector.Type == ConnectorType.Output)
            {
                ImpObservableCollection<ConnectionViewModel> leftConnections = _connector.AttachedConnections;
                foreach (ConnectionViewModel connection in leftConnections)
                {
                    connection.Visibility = Visibility.Hidden;
                }
            }
        }
       public  void  Update()
        {
            for(int i=0;i<listObserver.Count;i++)
            {
                listObserver[i].Update();
            }
        }

       public NodeViewModel CreateNode(Node _node,Point nodeLocation, bool centerNode)
       {

           var node = new NodeViewModel(_node);
           
           node.X = nodeLocation.X;
           node.Y = nodeLocation.Y;

           CreateNodeProcess(centerNode, node);

           return node;
       }

        public NodeViewModel CreateNode(Node _node, bool centerNode)
        {
                      
            var node = new NodeViewModel(_node);
            node.X = _node.X;
            node.Y = _node.Y;

            CreateNodeProcess(centerNode, node);            
            return node;
        }

        private void CreateNodeProcess(bool centerNode, NodeViewModel node)
        {
            bool exist = false;
            node.LeftConnectors.Add(new ConnectorViewModel("In1", node));

            node.RightConnectors.Add(new ConnectorViewModel("Out1", node));

            if (centerNode)
            {
                EventHandler<EventArgs> sizeChangedEventHandler = null;
                sizeChangedEventHandler =
                    delegate(object sender, EventArgs e)
                    {
                        node.X -= node.Size.Width / 2;
                        node.Y -= node.Size.Height / 2;

                        node.SizeChanged -= sizeChangedEventHandler;
                    };
                node.SizeChanged += sizeChangedEventHandler;
            }

            node.Size = new Size(120.0, 44.96);
            //
            // Add the node to the view-model.
            //
            do
            {
                exist = ExitNodeAt(node);
                if (exist)
                {
                    node.Y = node.Y + 80;
                }
            } while (exist);
            node.IsSelected = node.NodeData.IsSelected;
            this.Network.Nodes.Add(node);
        }


        public void Back()
        {
            if (currenCommand >= 0 && currenCommand < commandList.Count)
            {
                this.commandList[currenCommand].UndoExcute();
                currenCommand--;
                App.Synchronize();
            }
        }

        public void Next()
        {
            
            if (currenCommand >= -1 && currenCommand < commandList.Count-1)
            {
                currenCommand++;
                this.commandList[currenCommand].Excute();
                App.Synchronize();
            }
        }
        int currenCommand = -1;
        public void CreateLogicNode(double x, double y)
        {
            Node n = new Node();
            n.Name = "NewNode";
            n.X = x;
            n.Y = y;
            CheckAndChange(n,true);
            this.ViewNode.AddNode(n);
            AddCommandAdd(n);
           // DataLayer.AddNodeCommand
            App.Synchronize();
        }

        public void AddCommandAdd(Node _node)
        {
            AddNodeCommand command = new AddNodeCommand(_node);

            AddCommand(command);
        }

        private void AddCommand(ActionCommand command)
        {
            currenCommand++;
            if (currenCommand == this.commandList.Count)
            {
                commandList.Add(command);
            }
            if (currenCommand < this.commandList.Count)
            {
                int count = this.commandList.Count - 1 - currenCommand;
                commandList.RemoveRange(currenCommand, count);
                commandList[currenCommand] = command;

            }
        }
        public void AddCommandDelete(Node _node)
        {
            DeleteNodeCommand command = new DeleteNodeCommand(_node);
            AddCommand(command);
        }
        /// <summary>
        /// Utility method to delete a connection from the view-model.
        /// </summary>
        public void DeleteConnection(ConnectionViewModel connection)
        {
            this.Network.RemoveConnection(connection);
        }

        public void AddNodeToEditor(NodeViewModel _parent, Node _node)
        {

        }
        #region Private Methods

    

        public void PopulateData(MindMap mindMap)
        {
            //
            // Create a network, the root of the view-model.
            //
            
            this.Network = new NetworkViewModel();

            this.viewNode = mindMap.RootNode;

            NodeViewModel root = CreateNode(mindMap.RootNode, false);
            root.MyBrush.Color = Colors.Orange;
            CreateChildNode(viewNode, root);
 
            viewNode.UpdateOrder(0);
        }

        public void PopulateData(Node node)
        {
            //
            // Create a network, the root of the view-model.
            //
            this.Network = new NetworkViewModel();

            NodeViewModel nodetemp = CreateNode(node, false);
            nodetemp.MyBrush.Color = Colors.Orange;
            CreateChildNode(node, nodetemp);


            this.viewNode = node;
            viewNode.UpdateOrder(0);
        }

        private void AddNodeModelToRight(Node _node,NodeViewModel _parentNodeModel, double rightX, double rightY)
        {
           // _node.X = rightX;
           // _node.Y = rightY;
           // string name = _node.Name;
            _node.Direction = right;
            bool isExit = false;
            if (_node.Isfirst)
            {
                _node.X = rightX+ _parentNodeModel.NodeData.ComputeWidth();
                _node.Y = rightY;
            }
            NodeViewModel nodetemp = CreateNode(_node, false);
            nodetemp.LeftConnectors[0].Type = ConnectorType.Input;            
            do
            {
                isExit = ExitNodeAt(nodetemp);
                if (isExit)
                {
                    rightY += 80;
                    nodetemp.Y = rightY;
                }
            } while (isExit);
            
            ConnectionViewModel connection = new ConnectionViewModel();
            connection.SourceConnector = _parentNodeModel.RightConnectors[0];
            connection.DestConnector = nodetemp.LeftConnectors[0];

            this.Network.AddConnection(connection);
            
            CreateChildNode(_node, nodetemp);
            
        }

        

        private void AddNodeModelToLeft(Node _node, NodeViewModel _parentNodeModel, double leftX, double leftY)
        {
           //_node.X = leftX;
          // _node.Y = leftY;
            bool isExit = false;
            _node.Direction = left;
            if (_node.Isfirst)
            {
                _node.X = leftX - _node.ComputeWidth();
                _node.Y = leftY;
            }
            NodeViewModel nodetemp =  CreateNode(_node, false);
            
           
            nodetemp.RightConnectors[0].Type = ConnectorType.Input;
            do
            {
                isExit = ExitNodeAt(nodetemp);
                if (isExit)
                {
                    leftY += 80;
                    nodetemp.Y = leftY;
                }
            } while (isExit);
            ConnectionViewModel connection = new ConnectionViewModel();
            connection.SourceConnector = _parentNodeModel.LeftConnectors[0];
            connection.DestConnector = nodetemp.RightConnectors[0];

            this.Network.AddConnection(connection);
            
            CreateChildNode(_node, nodetemp);
        }

        


        public bool ExitNodeAt(NodeViewModel node)
        {
            bool rs = false;
            for (int i = 0; i < this.network.Nodes.Count; i++)
            {
                if (!node.Name.Equals(this.network.Nodes[i].Name))
                {                    
                    if (CheckCollision(node, this.network.Nodes[i]))
                    {
                        return true;
                    }
                }              
              
            }
            return rs;
        }
        public void CreateNode(Node _node, NodeViewModel _parentNodeModel)
        {
            if (_parentNodeModel == null)
                return;
            double rightX = _parentNodeModel.X + 150;
            double leftX = _parentNodeModel.X - 150;
            double rightY = _parentNodeModel.Y;
            double leftY = _parentNodeModel.Y;

            if (_parentNodeModel.OutConnector == 0)
            {
                MessageBox.Show("Node co den 2 node cha");
                return;
            }
            if (_parentNodeModel.OutConnector == 2)
            {
                AddNodeModelToRight(_node, _parentNodeModel,rightX,rightY);
                rightY += 100;
                return;
            }
            if (_parentNodeModel.OutConnector == 1)
            {
                if (_parentNodeModel.LeftConnectors[0].Type == ConnectorType.Output || _parentNodeModel.LeftConnectors[0].Type == ConnectorType.Undefined)
                {
                    AddNodeModelToLeft(_node, _parentNodeModel, leftX, leftY);
                    leftY += 100;
                    return;
                }
                if (_parentNodeModel.RightConnectors[0].Type == ConnectorType.Output || _parentNodeModel.RightConnectors[0].Type == ConnectorType.Undefined)
                {
                    AddNodeModelToRight(_node, _parentNodeModel, rightX, rightY);
                    rightY += 100;
                    return;
                }
            }
            
        }

        public void CreateChildNode(Node _parentNode, NodeViewModel _parentNodeModel)
        {

            if (_parentNode.ChildrenNodeList != null)
            {
                double rightX = _parentNodeModel.X + 50;
                double leftX = _parentNodeModel.X - 90;
                double rightY = _parentNodeModel.Y;
                double leftY = _parentNodeModel.Y;
                int count = _parentNode.ChildrenNodeList.Count;
                if (_parentNodeModel.OutConnector == 0)
                {
                    MessageBox.Show("Node co den 2 node cha");
                    return;
                }

                foreach(Node node in _parentNode.ChildrenNodeList)
                {
                    switch (node.Direction)
                    {
                        case left:
                            AddNodeModelToLeft(node, _parentNodeModel, leftX, leftY);
                            break;
                        case right:
                            AddNodeModelToRight(node, _parentNodeModel, rightX, rightY);
                            break;
                        default :
                            AddNodeModelToRight(node, _parentNodeModel, rightX, rightY);
                            break;
                    }
                }                  
            }
        }

        public NodeViewModel CreateNodeAt(Node _node, double x, double y)
        {
            _node.X = x;
            _node.Y = y;
           NodeViewModel nodeViewModel =  this.CreateNode(_node, false);
           this.CreateChildNode(_node, nodeViewModel);

           return nodeViewModel;
        }

        public NodeViewModel FindNodeByName(string name)
        {
            NodeViewModel rs =null;
            for(int i = 0;i< this.network.Nodes.Count;i++)
            {
                if (this.network.Nodes[i].Name.Equals(name))
                    rs = this.network.Nodes[i];
            }

            return rs;
        }


       
        public void InsertNodeLogic()
        {
            int currentSelected = -1;
            int countSelected = 0;
            NodeViewModel currentNode = null;
            for (int i = 0; i < network.Nodes.Count; i++)
            {
                if (network.Nodes[i].IsSelected)
                {
                    countSelected++;
                    currentSelected = i;
                    currentNode = network.Nodes[i];
                }
            }
            if (countSelected == 1)
            {
                // NodeViewModel node = CreateNode(
                currentNode.IsSelected = false;
                Node nodeAdded = new Node();
                nodeAdded.Name = "new node";
                nodeAdded.IsSelected = true;
                ConnecteNodeLogic(nodeAdded, currentNode);
                AddCommandAdd(nodeAdded);
            }
           // Update();
            
        }

        public void EnterCreateNodeLogic()
        {
            int currentSelected = -1;
            int countSelected = 0;
            NodeViewModel currentNode = null;
            for (int i = 0; i < network.Nodes.Count; i++)
            {
                if (network.Nodes[i].IsSelected)
                {
                    countSelected++;
                    currentSelected = i;
                    currentNode = network.Nodes[i];
                }
            }
            if (countSelected == 1 && !currentNode.IsTextChange)
            {               
                NodeViewModel parentNode = GetParentNodeVM(currentNode);
                currentNode.IsSelected = false;
                Node nodeAdded = new Node();
                nodeAdded.Name = "new node";
                nodeAdded.IsSelected = true;
                if (parentNode != null)
                {
                    ConnecteNodeLogic(nodeAdded, parentNode);                    
                }
                AddCommandAdd(nodeAdded);
            }
           // Update();
        }

        public NodeViewModel GetParentNodeVM(NodeViewModel node)
        {
            NodeViewModel rs = null;
            //ConnectorViewModel connector = null;
            //if (node.LeftConnectors[0].Type == ConnectorType.Input)
            //{
            //    connector = node.LeftConnectors[0];
            //}
            //if (node.RightConnectors[0].Type == ConnectorType.Input)
            //{
            //    connector = node.RightConnectors[0];
            //}
            //if (connector != null)
            //{
            //    List<ConnectionViewModel> connection = FindListConnection(connector);
            //    if (connection.Count == 1)
            //    {
            //        rs = connection[0].SourceConnector.OwnerNode;
            //    }
            //}
            rs = GetParentNodeVMWithConnector(node.RightConnectors[0]);
            if(rs != null)
                return rs;
            rs = GetParentNodeVMWithConnector(node.LeftConnectors[0]);
            return rs;
        }

        public NodeViewModel GetParentNodeVMWithConnector(ConnectorViewModel connector)
        {
            foreach (ConnectionViewModel connection in connector.AttachedConnections)
            {
                if (connection.DestConnector == connector)
                {
                    return connection.SourceConnector.OwnerNode;
                }
            }
            return null;
        }
       
        private bool CheckCollision(NodeViewModel node1, NodeViewModel node2)
        {
            bool retval = false;

            Point ptTopLeft = new Point(node1.X,node1.Y);
            Point ptBottomRight = new Point(node1.X + node1.Size.Width, node1.Y + node1.Size.Height);
            Rect r1 = new Rect(ptTopLeft, ptBottomRight);

            //System.Diagnostics.Debug.WriteLine("+++x:" + ptTopLeft.X.ToString() + " Y " + ptTopLeft.Y.ToString() + " " + ptBottomRight.X.ToString() + " " + ptBottomRight.Y.ToString());


            Point ptTopLeft2 = new Point(node2.X, node2.Y);
            Point ptBottomRight2 = new Point(node2.X + node2.Size.Width, node2.Y + node2.Size.Height);
            Rect r2 = new Rect(ptTopLeft2, ptBottomRight2);

            r1.Intersect(r2);
            if (!r1.IsEmpty)
            {
                retval = true;
            }
            return retval;
        }

        public void NodeDragCompleted(NodeViewModel node)
        {
            
            foreach(NodeViewModel nodeChecked in this.network.Nodes)
            {
                if(CheckCollision(node,nodeChecked) && !nodeChecked.Name.Equals(node.Name))
                {
                    NodeViewModel parentNode = GetParentNodeVM(node);
                    if (parentNode == null && node.NodeData.GetType().ToString() != "DataLayer.RootNode")
                    {
                        ConnecteNodeLogic(node, nodeChecked);
                    }
                }
            }
            NodeViewModel tempNode = this.GetParentNodeVM(node);
            if (tempNode != null)
            {
                CheckAndReconnect(tempNode, node);
            }
        }

        private void CheckAndReconnect(NodeViewModel parent, NodeViewModel node)
        {
            if (parent.X + 50 < node.X && node.NodeData.Direction == left)
            {
                node.NodeData.Direction = right;
                ConnectionViewModel connection = FindConnectionExac(parent.LeftConnectors[0], node.RightConnectors[0]);
                this.DeleteConnection(connection);
                ConnectionViewModel newconnection = new ConnectionViewModel();
                newconnection.SourceConnector = parent.RightConnectors[0];
                newconnection.DestConnector = node.LeftConnectors[0];
                this.Network.AddConnection(newconnection);               
            }
            if (node.X + 50 < parent.X && node.NodeData.Direction == right)
            {
                node.NodeData.Direction = left;
                ConnectionViewModel connection = FindConnectionExac(parent.RightConnectors[0], node.LeftConnectors[0]);
                this.DeleteConnection(connection);
                ConnectionViewModel newconnection = new ConnectionViewModel();
                newconnection.SourceConnector = parent.LeftConnectors[0];
                newconnection.DestConnector = node.RightConnectors[0];
                this.Network.AddConnection(newconnection);   
            }
        }

        public void CheckAndChange(Node _node,bool isNew)
        {
            int itemId = 0;
            string rootName = _node.Name;
            string newName = rootName;
            do
            {                
                NodeViewModel existNode = CheckNodeExist(newName);
                if (_node.Name.Length == 0 || (existNode != null && !existNode.NodeData.Equals(_node)))
                {
                    itemId ++;
                    
                    if (isNew)
                        _node.Name = newName;
                    else
                    {
                        newName = rootName + " (" + itemId + ")";
                        MessageBoxResult msResult = MessageBox.Show("\"" + _node.Name + "\"" + " is already exists, do you want to change to \"" + newName + "\" ? ", "Are you sure?", MessageBoxButton.YesNo);
                        if (msResult == MessageBoxResult.No)
                             newName = rootName;
                    }
                }
                else
                    itemId = 0;
            } while (itemId != 0);
            _node.Name = newName;
        }

        //ham dung cho insert va enter
        public void ConnecteNodeLogic(Node _node, NodeViewModel _parentNodeModel)
        {
            Node source = _parentNodeModel.NodeData;
            CheckAndChange(_node,true);
            if (_parentNodeModel.OutConnector == 2)
            {
                int rightLimit = source.ChildrenNodeList.Count / 2;
                if (source.CountRightChildeNode() > rightLimit)
                {
                    _node.Direction = left;
                }
                else
                {
                    _node.Direction = right;
                }
            }
            else
            {
                if (_parentNodeModel.RightConnectors[0].Type == ConnectorType.Output || _parentNodeModel.RightConnectors[0].Type == ConnectorType.Undefined)
                {
                    _node.Direction = right;
                }
                if (_parentNodeModel.LeftConnectors[0].Type == ConnectorType.Output || _parentNodeModel.LeftConnectors[0].Type == ConnectorType.Undefined)
                {
                    _node.Direction = left;
                }
            }
            source.AddNode(_node);
            App.Synchronize();
        }

        
        // ham dung cho drag drop
        public void ConnecteNodeLogic(NodeViewModel _node, NodeViewModel _parentNodeModel)
        {
            Node source = _parentNodeModel.NodeData;
            Node dest = _node.NodeData;
            Node temp = new Node(dest);
            this.viewNode.RemoveNode(dest.Name);

            if (_parentNodeModel.OutConnector == 2)
            {
                int rightLimit = source.ChildrenNodeList.Count / 2;
                if (source.CountRightChildeNode() > rightLimit)
                {
                    temp.Direction = left;
                }
                else
                {
                    temp.Direction = right;
                }
            }
            else
            {
                if (_parentNodeModel.RightConnectors[0].Type == ConnectorType.Output || _parentNodeModel.RightConnectors[0].Type == ConnectorType.Undefined)
                {
                    temp.Direction = right;
                }
                if (_parentNodeModel.LeftConnectors[0].Type == ConnectorType.Output || _parentNodeModel.LeftConnectors[0].Type == ConnectorType.Undefined)
                {
                    temp.Direction = left;   
                }
            }
            source.AddNode(temp);
            App.Synchronize();

        }
        //public bool CheckNodeExist(string name)
        //{
        //    for (int i = 0; i < network.Nodes.Count; i++)
        //    {
        //        if(name.Equals(network.Nodes[i].Name))
        //            return true;
        //    }
        //    return false;
        //}

        public NodeViewModel CheckNodeExist(string name)
        {
            for (int i = 0; i < network.Nodes.Count; i++)
            {
                if (name.Equals(network.Nodes[i].Name))
                    return network.Nodes[i];
            }
            return null;
        }

        public int CountSelectedNode()
        {
            int rs = 0;
            foreach(NodeViewModel node in network.Nodes)
            {
                if (node.IsSelected)
                {
                    rs++;
                }
            }
            
            return rs;
        }

        public NodeViewModel GetFirstSelectedNode()
        {
            NodeViewModel rs = null;
            foreach (NodeViewModel item in this.network.Nodes)
            {
                if (item.IsSelected)
                    return item;
            }
            return rs;
        }
        #endregion Private Methods
    }
}

